function _funnySuffixGen() {
  function randStr(aLength) {
    var result = "";
    var source = "abcdefghijklmnopqrstuvwxvz";
    for (var i = 0; i < aLength; i++) {
      result += source.charAt(Math.floor(Math.random() * source.length));
    }
    return result;
  }

  var i;
  for (i = 0; i < 1000; i++) {
    // "rose.jpg" -> "rose_001.jpg", "rose_021.jpg" etc.
    yield ("00" + i).substr(-3);
  }
  for (i = 0; i < 10; i++) {
    // "rose.jpg" -> "rose_xaz.jpg", "rose_gkh.jpg" etc.
    yield randStr(3);
  }
  yield false;
}

function _URIsArrayToUniqueDstNamesArray(aArray) {
  function compareURI(x, y) {
    return (x[1] == y[1]);
  }
  let eltFilePathBasenameArray =
    deleteDupulicated(aArray, compareURI).map(function(x) {
      let [elt, uri] = x;
      let filepath = convertURIToFilePath(uri);
      if (!filepath) throw new Error("oops. not a local file. "+ uri);
      return [elt, filepath, sysBasename(filepath)];
    });
  // make a mapping table. Key is "basename". Value is a Array of its indices.
  let mapping = {};
  eltFilePathBasenameArray.forEach(function(x,i) {
                                     if (!mapping[x[2]]) mapping[x[2]] = [];
                                     mapping[x[2]].push(i);
                                   });
  for (var basename in mapping) {
    if (mapping[basename].length > 1) {
      // Now then, there exists duplicated basenames. Try to make them unique.
      mapping[basename].forEach(function(mappingIndex) {
        var uniqBasename = "";
        let [, base, ext] = decomposePath(basename);
        for (var gen = _funnySuffixGen(), suffix = gen.next(); suffix; suffix = gen.next()) {
          uniqBasename = ext ? base + "_" + suffix + "." + ext :
                               base + "_" + suffix;
          if (!mapping[uniqBasename]) break;
        }
        if (uniqBasename) {
          eltFilePathBasenameArray[mappingIndex][2] = uniqBasename;
          mapping[uniqBasename] = [mappingIndex];
        } else {
          throw new Error("failed to make basenames unique");
        }
      });
    }
  }
  return eltFilePathBasenameArray;
}

function storeHTML() {
  function getSrc(x) {
    if (x.tagName == "LINK" || x.tagName == "A") {
      if (/^file:/.test(x.href)) return [x, x.href];
    }
    if (x.tagName == "IMG"  || x.tagName == "SCRIPT") {
      if (/^file:/.test(x.src))  return [x, x.src];
    }
    return false;
  }
  function setSrc(x, value) {
    if (x.tagName == "LINK" || x.tagName == "A") {
      x.href = value;
    }
    if (x.tagName == "IMG"  || x.tagName == "SCRIPT") {
      x.src  = value;
    }
  }
  var contentDoc = window.content.document;
  // This check is absolutely IMPORTANT to avoid leaking local files.
  if (!/^file:/.test(contentDoc.location.href)) return contentDoc.location.href;

  var html = contentDoc.documentElement.cloneNode(true);
  var locals = filterMap([].concat($A(html.getElementsByTagName("a")),
                                   $A(html.getElementsByTagName("img")),
                                   $A(html.getElementsByTagName("script")),
                                   $A(html.getElementsByTagName("link"))),
                         getSrc);
  var now = new Date().getTime().toString();
  var storingURI = "http://localhost/musubi/" + now + "/";
  var $ftpHost = document.getElementById("ftp-host");
  var $ftpPort = document.getElementById("ftp-port");
  var $ftpUser = document.getElementById("ftp-user");
  var $ftpPass = document.getElementById("ftp-pass");
  callWithFtpConnection($ftpHost ? $ftpHost.value : "ftp://localhost",
                        function(conn) {
                          // Make a directory named {now}.
                          ftpMkdir(conn, now);
                          ftpChdir(conn, now);
                          // Make a directory named "files". This manner follows Firefox's "saveURL"
                          ftpMkdir(conn, "files");
                          ftpChdir(conn, "files");
                          _URIsArrayToUniqueDstNamesArray(locals).forEach(function(x, i) {
                            let [elt, filepath, uniqBasename] = x;
                            ftpPut(conn, filepath, uniqBasename);
                            let newLink = storingURI + "files/" + uniqBasename;
                            setSrc(elt, newLink);
                          });
                          ftpChdir(conn, "..");
                          // Store "index.html".
                          callWithInputString("<html>\n" + html.innerHTML + "\n</html>\n",
                                              function(inp) {
                                                ftpPutFromStream(conn, inp, "index.html");
                                              });
                        },
                        {
                          port:     $ftpPort ? parseInt($ftpPort.value, 10) : 21,
                          username: $ftpUser ? $ftpUser.value : "anonymous",
                          password: $ftpPass ? $ftpPass.value : "anonymous@"
                        });
  return storingURI;
}